// dynamic tree for collection navigation

(function () {
  var elem = function (value) {
    var name = function (value) {
      if (!(/\//.exec(value))) return value;
      return /\/([^\/]*)$/.exec(value).pop();
    };
    return {
      "id": value,
      "name": name(value),
      "data": {},
      "children": []
    };
  },
  TreeGen = new Class({
    Implements: Events,
    get: function (nodeId) {
      var prefix = 'http://desanti.org/collections/',
          url = 'http://desanti.org/endpoint.php?query=PREFIX+terms%3A+<http%3A%2F%2Fdesanti.org%2Fschemas%2Fcollections%23>%0D%0APREFIX+things%3A+<http%3A%2F%2Fdesanti.org%2Fcollections%2F>%0D%0ASELECT+%3Fcol+WHERE+{%0D%0A++things%3Aid+terms%3AparentOf+%3Fcol+.%0D%0A}&output=json';

      (new Request.JSON ({url: url.replace('id', encodeURIComponent(nodeId))})).get().addEvent('success', function (json) {
        var res, req;

        res = elem (nodeId);
        req = new Request.JSON ({link: 'chain', method: 'get'});
        req.children = [];
        req.addEvent('success', function (json) {
          var child = req.children.pop();
          json.results.bindings.each(function(binding) {
            child.children.push( elem( binding.col.value.replace(prefix, '') ) );
          });
          res.children.push(child);
          if(!req.$chain.length) {
            this.fireEvent('complete');
          }
        }.bind(this));

	if (json.results.bindings.length) {
          json.results.bindings.each(function(binding) {
            req.children.unshift(elem(binding.col.value.replace(prefix, '')));
            req.send({url: url.replace('id', encodeURIComponent(binding.col.value.replace(prefix, '')))});
          });
	} else {
	  this.fireEvent('complete');
	}
        this.res = res;
      }.bind(this));
      return this;
    }
  }),

  Log = {
      elem: false,
      write: function(text){
          if (!this.elem) 
              this.elem = $('log');
          this.elem.innerHTML = text;
          this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
      }
  },
  
  init = function(){
      var infovis = $('infovis');
      var w = infovis.offsetWidth, h = infovis.offsetHeight;
      //init canvas
      //Create a new canvas instance.
      var canvas = new Canvas('mycanvas', {
          'injectInto': 'infovis',
          'width': w,
          'height': h,
          'backgroundColor': '#1a1a1a'
      });
      //end

      //Implement a node rendering function called 'nodeline' that plots a straight line
      //when contracting or expanding a subtree.
      ST.Plot.NodeTypes.implement({
          'nodeline': function(node, canvas, animating) {
              if(animating === 'expand' || animating === 'contract') {
                  var pos = node.pos.getc(true), nconfig = this.node, data = node.data;
                  var width  = nconfig.width, height = nconfig.height;
                  var algnPos = this.getAlignedPos(pos, width, height);
                  var ctx = canvas.getCtx(), ort = this.config.orientation;
                  ctx.beginPath();
                  if(ort == 'left' || ort == 'right') {
                      ctx.moveTo(algnPos.x, algnPos.y + height / 2);
                      ctx.lineTo(algnPos.x + width, algnPos.y + height / 2);
                  } else {
                      ctx.moveTo(algnPos.x + width / 2, algnPos.y);
                      ctx.lineTo(algnPos.x + width / 2, algnPos.y + height);
                  }
                  ctx.stroke();
              } 
          }
      });
  
      //init st
      //Create a new ST instance
      var st = new ST(canvas, {
          //set duration for the animation
          duration: 800,
          //set animation transition type
          transition: Trans.Quart.easeInOut,
          //set distance between node and its children
          levelDistance: 50,
          //set max levels to show. Useful when used with
          //the request method for requesting trees of specific depth
          levelsToShow: 2,
          //set node and edge styles
          //set overridable=true for styling individual
          //nodes or edges
          Node: {
              height: 20,
              width: 40,
              //use a custom
              //node rendering function
              type: 'nodeline',
              color:'#23A4FF',
              lineWidth: 2,
              align:"center",
              overridable: true
          },
          
          Edge: {
              type: 'bezier',
              lineWidth: 2,
              color:'#23A4FF',
              overridable: true
          },
          
          //Add a request method for requesting on-demand json trees. 
          request: function(nodeId, level, onComplete) {
            (new TreeGen()).get(nodeId).addEvent('complete', function () { 
	      onComplete.onComplete(nodeId, this.res); 
	    });
          },
          
          onBeforeCompute: function(node){
              Log.write("loading " + node.name);
              document.getElementById( "viewCollection" ).onclick = function( )
              {
                 self.opener.DESANTI.openPage( "http://desanti.org/collections/" + node.id + "/0001" ); 
                 self.opener.focus( );
              }
          },
          
          onAfterCompute: function(){
              Log.write("done");
          },
          
          //This method is called on DOM label creation.
          //Use this method to add event handlers and styles to
          //your node.
          onCreateLabel: function(label, node){
              label.id = node.id;            
              label.innerHTML = node.name;
              label.onclick = function(){
                  st.onClick(node.id);
              };
              //set label styles
              var style = label.style;
              style.width = 40 + 'px';
              style.height = 17 + 'px';            
              style.cursor = 'pointer';
              style.color = '#fff';
              //style.backgroundColor = '#1a1a1a';
              style.fontSize = '0.8em';
              style.textAlign= 'center';
              style.textDecoration = 'underline';
              style.paddingTop = '3px';
          },
          
          //This method is called right before plotting
          //a node. It's useful for changing an individual node
          //style properties before plotting it.
          //The data properties prefixed with a dollar
          //sign will override the global node style properties.
          onBeforePlotNode: function(node){
              //add some color to the nodes in the path between the
              //root node and the selected node.
              if (node.selected) {
                  node.data.$color = "#ff7";
              }
              else {
                  delete node.data.$color;
              }
          },
          
          //This method is called right before plotting
          //an edge. It's useful for changing an individual edge
          //style properties before plotting it.
          //Edge data proprties prefixed with a dollar sign will
          //override the Edge global style properties.
          onBeforePlotLine: function(adj){
              if (adj.nodeFrom.selected && adj.nodeTo.selected) {
                  adj.data.$color = "#eed";
                  adj.data.$lineWidth = 3;
              }
              else {
                  delete adj.data.$color;
                  delete adj.data.$lineWidth;
              }
          }
      });
      //load json data
      st.loadJSON(elem($('collectionId').get('value')));
      //compute node positions and layout
      st.compute();
      //emulate a click on the root node.
      st.onClick(st.root);
      //end
  };

  window.addEvent('domready', init);
})();
